home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-04-27 | 6.1 KB | 196 lines | [TEXT/????] |
- ;;; $Header: pseries.scm,v 1.4 88/01/26 07:44:32 GMT gjs Exp $
- ;;;; PS.SCM: Power-series arithmetic using infinite streams.
-
- (if-mit
- (declare (usual-integrations = + - * /
- zero? 1+ -1+
- ;; truncate round floor ceiling
- sqrt exp log sin cos)))
-
- ;;; Power series may be represented by (infinite) streams of
- ;;; coefficients.
-
- ;;; Thus we may represent the series
- ;;; a0 + a1*x + a2*x^2 + a3*x^3 + ...
- ;;; by the stream {a0 a1 a2 a3 ...}
-
- ;;; In our series the coefficients are manipulated with the
- ;;; procedures ADD, MUL, SUB, DIV, rather than +, *, -, /, so
- ;;; that we may use rational arithmetic, complex arithmetic,
- ;;; or polynomial arithmetic... as desired.
- ;;; Here we specify the map:
-
- (define add +)
- (define sub -)
- (define mul *)
- (define div /)
- (define raise expt)
- (define zero 0)
-
- ;;; The following procedures provide a set of capabilities for
- ;;; manipulating series.
-
- ;;; c*(a0 + a1*x + a2*x^2 + a3*x^3 + ...)
- ;;; = c*a0 + c*a1*x + c*a2*x^2 + c*a3*x^3 + ...)
-
- (define scale-series
- (lambda (c s)
- (map-stream (lambda (x) (mul c x))
- s)))
-
- ;;; (a0 + a1*x + a2*x^2 + ...) + (b0 + b1*x + b2*x^2 + ...)
- ;;; = (a0+b0) + (a1+b1)*x + (a2+b2)*x^2 + ...
-
- (define add-series
- (lambda (s1 s2)
- (map-streams add s1 s2)))
-
- (define sub-series
- (lambda (s1 s2)
- (map-streams sub s1 s2)))
-
-
- ;;; (a0 + a1*x + a2*x^2 + ...) * (b0 + b1*x + b2*x^2 + ...)
- ;;; = a0*b0 + (a0*b1+a1*b0)*x + (a0*b2+a1*b1+a2*b0)*x^2 + ...
- ;;; Each coefficient of the result is formed by reversing an initial
- ;;; segment of one series, multiplying it by the coefficients of an
- ;;; initial segment of the other series, and accumulating the
- ;;; products.
-
- (define mul-series
- (lambda (s1 s2)
- (map-streams inner-product-segments
- (map-stream reverse (initial-segments-series s1))
- (initial-segments-series s2))))
-
- (define initial-segments-series
- (let ()
- (define i-s-helper
- (lambda (seg series)
- (let ((nseg (cons (head series) seg)))
- (cons-stream nseg
- (i-s-helper nseg
- (tail series))))))
- (lambda (s)
- (i-s-helper '() s))))
-
- (define inner-product-segments
- (lambda (seg1 seg2)
- (reduce add (map mul seg1 seg2))))
-
- (define div-series
- (let ()
- (define (div-helper v0)
- (lambda (un ws rvs)
- (div (sub un (inner-product-segments ws rvs)) v0)))
- (lambda (u v)
- (define v0 (head v))
- (define w
- (cons-stream
- (div (head u) v0)
- (map-streams (div-helper v0)
- (tail u)
- (initial-segments-series w)
- (map-stream reverse
- (initial-segments-series (tail v))))))
- w)))
-
-
- (define (expt-series v a) ;A a number.
- (cond ((zero? (head v))
- (error "Cannot raise series to power -- no A0 term"))
- ((= (head v) 1)
- (expt-monic-series v a))
- (else
- (let ((v0^a (raise (head v) a)))
- (map-stream (lambda (wi) (mul wi v0^a))
- (expt-monic-series (map-stream (lambda (vi)
- (div vi (head v)))
- v)
- a))))))
-
- (define (expt-monic-series v a)
- (define w
- (cons-stream 1
- (map-streams (lambda (w s1 s2) ;weighted inner product
- (reduce add (map mul w (map mul s1 s2))))
- (expt-weights (+ a 1))
- (initial-segments-series (tail v))
- (map-stream reverse
- (initial-segments-series w)))))
- w)
-
- (define (expt-weights a+1)
- (define (sloop n)
- (let ((a+1/n (/ a+1 n)))
- (define (wloop k l)
- (if (> k n)
- l
- (wloop (+ k 1) (cons (- (* k a+1/n) 1) l))))
- (cons-stream (wloop 1 '()) (sloop (+ n 1)))))
- (sloop 1))
-
- (define deriv-series
- (let ()
- (define (deriv-iter s n)
- (if (null? s)
- '()
- (cons-stream (mul n (head s))
- (deriv-iter (tail s) (+ n 1)))))
- (lambda (s) (deriv-iter (tail s) 1))))
-
-
- ;;; The integral of a series
- ;;; a0 + a1*x + a2*x^2 + a3*x^3 + ...
- ;;; is c + a0*x + a1*x^2/2 + a2*x^3/3 + ...
- ;;; and is returned by the procedure INTEGRATE-SERIES which
- ;;; takes the "initial condition" c as a required argument.
- ;;; For technical reasons, we are unable to use INTEGRATE-SERIES
- ;;; with mutual-recursion as in
- ;;; (define cos-series (integrate-series sin-series 1)) ;DOESN'T
- ;;; (define sin-series (integrate-series cos-series 0)) ;WORK!
- ;;; However, we can achieve the desired effect by postponing the
- ;;; attachment of the constant term, as follows. We use the procedure
- ;;; INTEGRAL-SERIES-TAIL which returns the indefinite integral
- ;;; part of the integrated series, i.e., {a0 a1/2 a2/3 a3/4 ...}.
- ;;; Now, the mutual-recursion above can be made to work:
- ;;; (define cos-series (cons-stream 1 (integral-series-tail sin-series)))
- ;;; (define sin-series (cons-stream 0 (integral-series-tail cos-series)))
-
- (define (integrate-series series constant-term)
- (cons-stream constant-term (integral-series-tail series)))
-
- (define integral-series-tail
- (let ()
- (define integrate-helper
- (lambda (s n)
- (cons-stream (div (head s) n)
- (integrate-helper (tail s) (+ n 1)))))
- (lambda (series)
- (integrate-helper series 1))))
-
-
-
- ;;; A power series may be evaluated at a particular
- ;;; point. Given a stream that represents a series, the
- ;;; following procedure will produce a procedure that
- ;;; when given an x will produce a stream of pairs -- the
- ;;; first element of each pair is a partial sum, and the next
- ;;; element of the pair is the next (first ignored) term in
- ;;; the sum. Note that this is a sequence, not a series.
-
- (define partial-sums
- (let ((partial-sums-helper
- (lambda (x)
- (define loop
- (lambda (series sum xn)
- (let ((term (mul xn (head series))))
- (cons-stream (list sum term)
- (loop (tail series)
- (add sum term)
- (mul xn x))))))
- loop)))
- (lambda (series)
- (lambda (x)
- ((partial-sums-helper x) series 0 1)))))
-